package com.bitcola.chainserver.chain.trx.utils;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.LinkedList;

import org.bouncycastle.asn1.x9.X9IntegerConverter;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.signers.ECDSASigner;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.math.ec.ECAlgorithms;
import org.bouncycastle.math.ec.ECPoint;

import javax.xml.bind.DatatypeConverter;

public class Secp256k1Util {
    static {
        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
    }
    private static final String RANDOM_NUMBER_ALGORITHM="SHA1PRNG";
    private static final String RANDOM_NUMBER_ALGORITHM_PROVIDER="sun";
    static KeyPair createSecp256k1KeyPair(SecureRandom random)
            throws NoSuchProviderException, NoSuchAlgorithmException,
            InvalidAlgorithmParameterException {

        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ECDSA", "BC");
        ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec("secp256k1");
        if (random != null) {
            keyPairGenerator.initialize(ecGenParameterSpec, random);
        } else {
            keyPairGenerator.initialize(ecGenParameterSpec);
        }
        return keyPairGenerator.generateKeyPair();
    }

    public static void main(String[] args) throws Exception {

        var s= ByteUtils.toByteArray("b481ebd1376bc6ca234b4a39232bdda9e0aa7e983123a33ef5c65d140300a05c");
        KeyPair keyPair = createSecp256k1KeyPair( new SecureRandom());
        PublicKey publicKey1 = keyPair.getPublic();
        PrivateKey privateKey1 = keyPair.getPrivate();
        System.out.println(1);
//        byte []data={44, (byte) 183, (byte) 220, 53, (byte) 177, (byte) 145, 18, 90, (byte) 213, 19, (byte) 137, 54, 53, 98, (byte) 164, 119, 8, 48, 87, (byte) 184, 72, (byte) 214, (byte) 226, 127, (byte) 196, 32, (byte) 156, (byte) 206, (byte) 131, (byte) 160, (byte) 244, 16};
//        byte [] prib= {23, 92, 82, 112, (byte) 183, (byte) 208, 83, (byte) 143, 40, 46, (byte) 137, (byte) 217, 43,
//                28, (byte) 135, (byte) 195, (byte) 219, 21, (byte) 171, (byte) 165, (byte) 192, 15, 89, (byte) 251, 49, (byte) 245, (byte) 179, (byte) 159, 117, 120, (byte) 242, 75};
//        byte [] pubb= {3, (byte) 255, 58, 65, (byte) 182, (byte) 190, 96,
//                120, (byte) 144, 50, 9, (byte) 175, 38, 84, 105, 61, 18, (byte) 164,
//                21, 76, 103, 93, 88, (byte) 184, (byte) 238, 81, 35, 46, (byte) 229, (byte) 148, 7, 82, (byte) 167};
        byte [] prib=ByteUtils.toByteArray("b481ebd1376bc6ca234b4a39232bdda9e0aa7e983123a33ef5c65d140300a05c");
        byte [] pubb=ByteUtils.toByteArray("023a1a35f39b9a53909d8220a06042a1822b16e894595f82af169a60a5ebd1cc0e");
        byte   []data=ByteUtils.toByteArray("a8ba940f02fa266bd5ea78f2fafd79468445592fc71c6c5d488e22037f45b86c165587d86b5f633df2e68d0f6d14e5450d0aa47a42ebd6994e413d1636125be1");
        var pub2=getPrivateKey("b481ebd1376bc6ca234b4a39232bdda9e0aa7e983123a33ef5c65d140300a05c");
        var pri2=getPublicKey("023a1a35f39b9a53909d8220a06042a1822b16e894595f82af169a60a5ebd1cc0e");
//        var signResult= signData(data,pri2);
//        System.out.println(verifySign(data,pub2,signResult));


    }



    /**
     * 从string转private key
     */
    public static PrivateKey getPrivateKey(String key) throws Exception {
        byte[] bytes = DatatypeConverter.parseHexBinary(key);

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        return keyFactory.generatePrivate(keySpec);
    }

    /**
     * 从string转public key
     */
    public static PublicKey getPublicKey(String key) throws Exception {
        byte[] bytes = DatatypeConverter.parseHexBinary(key);

        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        return keyFactory.generatePublic(keySpec);
    }


    // 读取公钥, encodedKey为从文件中读取到的byte[]数组
    public static PublicKey loadPublicKey(byte[] encodedKey)
            throws NoSuchAlgorithmException, InvalidKeySpecException {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);
        KeyFactory keyFactory = KeyFactory.getInstance("ECDSA");
        return keyFactory.generatePublic(keySpec);
    }

    // 读取私钥
    public static PrivateKey loadPrivateKey(byte[] encodedKey)
            throws NoSuchAlgorithmException, InvalidKeySpecException{
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);
        KeyFactory keyFactory = KeyFactory.getInstance("ECDSA");
        return keyFactory.generatePrivate(keySpec);
    }

    /**
     * 随机生成私钥
     * @param privateKey
     * @return
     */
    public static byte[] generatePrivateKey(byte[] privateKey) {
        SecureRandom secureRandom = null;
        try {
            secureRandom = secureRandom.getInstance(RANDOM_NUMBER_ALGORITHM,
                    RANDOM_NUMBER_ALGORITHM_PROVIDER);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchProviderException e) {
            e.printStackTrace();
        }
        BigInteger privateKeyCheck = BigInteger.ZERO;
        //随机选取一个32字节的数、大小介于1-
        //0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF BAAE DCE6 AF48 A03B BFD2 5E8C D036 4141
        BigInteger maxKey = new BigInteger("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140",16);
        //产生实际字节数组
        byte[] privateKeyAttempt = new byte[32];
        secureRandom.nextBytes(privateKeyAttempt);
        privateKeyCheck =  new BigInteger(1,privateKeyAttempt);
        while(privateKeyCheck.compareTo(BigInteger.ZERO)==0 || privateKeyCheck.compareTo(maxKey)==1) {
            secureRandom.nextBytes(privateKeyAttempt);
            privateKeyCheck = new BigInteger(1,privateKeyAttempt);
        }
        return privateKeyAttempt;
    }

    /**
     * 利用私钥生成对应公钥
     * @param privateKey
     * @return
     */
    public static byte[] generatePublicKey(byte[] privateKey) {
        ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1");
        ECPoint pointQ = spec.getG().multiply(new BigInteger(1,privateKey));
        return pointQ.getEncoded(true);

    }



    public static byte[] signData( byte[] data, PrivateKey key) throws Exception {
        Signature signer = Signature.getInstance("SHA256withECDSA");
        signer.initSign(key);
        signer.update(data);
        return (signer.sign());
    }

    public static boolean verifySign( byte[] data, PublicKey key, byte[] sig) throws Exception {
        Signature signer = Signature.getInstance("SHA256withECDSA");
        signer.initVerify(key);
        signer.update(data);
        return (signer.verify(sig));
    }

    /**
     * 根据私钥的签名推算对应得公钥
     * @return
     */
    public static byte[] recoverPublicKey(byte[] sigR,byte[] sigS, byte[] sigV,byte[] message) {
        ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1");
        BigInteger pointN = spec.getN();
        try {
            BigInteger pointX = new BigInteger(1,sigR);
            X9IntegerConverter x9 = new X9IntegerConverter();
            byte[] compEnc =x9.integerToBytes(pointX, 1+x9.getByteLength(spec.getCurve()));
            compEnc[0] = (byte)((sigV[0] &1)==1?0x03:0x02);
            ECPoint pointR= spec.getCurve().decodePoint(compEnc);
            if(!pointR.multiply(pointN).isInfinity()) {
                return new byte[0];
            }

            BigInteger pointE = new BigInteger(1,message);
            BigInteger pointEInv= BigInteger.ZERO.subtract(pointE).mod(pointN);
            BigInteger pointRInv= new BigInteger(1,sigR).modInverse(pointN);
            BigInteger srinv = pointRInv.multiply(new BigInteger(1,sigS)).mod(pointN);
            BigInteger pointEInvRInv = pointRInv.multiply(pointEInv).mod(pointN);
            ECPoint pointQ = ECAlgorithms.sumOfTwoMultiplies(spec.getG(), pointEInvRInv, pointR, srinv);
            byte[] pointQBytes = pointQ.getEncoded(false);
            return pointQBytes;
        } catch (Exception e) {
            //
        }
        return new byte[0];
    }


    /**
     * 验证签名与公钥是否匹配
     * @return
     */
    public static boolean verifySignature(byte[] sigR,byte[] sigS, byte[] sigV,byte[] message,byte[] pubKey) {
        byte[] arrPubKey = recoverPublicKey(sigR, sigS, sigV, message);
        if(ByteUtils.toHexString(arrPubKey).equals(ByteUtils.toHexString(pubKey))) {
            return true;
        }else {
            return false;
        }
    }



}